/**
 * 
 */
package Zeus;
import java.io.*;
import java.net.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;

import VBox.Hyperviser;
import VBox.Job;
import VBox.OS;
import VBox.VM;

import Core.DB;
import Core.Dispatcher;
import Core.Login;
import Core.Settings;
public class Server{
	ServerSocket serverSocket;
	static Logger log = Logger.getAnonymousLogger();
	static ServerMenu menu;
	//Settings settings;
	Dispatcher disp; 
	Login auth = new Login();
	String OWNER;
	Job job = new Job();
	Settings settings = new Settings();
	Hyperviser vmm = new Hyperviser(settings.VMMSettings);
	DB db = new DB();
	OutputStream out = null;
	Socket connection = null;
	String pwd = null;
	String message = null ;
	InputStream textLineIn1 = null;
	int socket = 8002;
	Server(){}
	
	public class ServerMenu implements Runnable {
		public void run() {
			for(int i = 0; i < 40; i++){
				try {
					listenForMessage();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * @throws UnknownHostException
	 * @throws IOException
	 */
	public void run() throws UnknownHostException, IOException
	{	

//		System.out.println(  listFiles( "/home/sherin") );	
	
		
	//	getConnection();	
		//for(int i = 0; i < 40; i++){
		//	listenForMessage();
		//}
	//	closeConnection();
	
		
		
		menu = new ServerMenu();
		Settings settings = new Settings();
		Dispatcher disp = new Dispatcher(settings.VMMSettings); 
		try {
			//server.run();
			// Starts the server
			
			ExecutorService pool = Executors.newFixedThreadPool(2);
			 pool.submit(menu);
			 log.info("Submitted Menu to thread");
			 pool.submit(disp);		 
			 log.info("Dispatcher submitted on a Thread");
			 
			 
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	void listenForMessage() throws IOException{
		getConnection();	
		message = readMessage();
		System.out.println(message);
		processRequest(message);
		closeConnection();
	}
	
	private void closeConnection() throws IOException {
		serverSocket.close();
		connection.close();
		
	}
	private void getConnection() throws IOException{		
		
		serverSocket = new ServerSocket(socket, 10);    //making the connections
		System.out.println("Socket created");
		connection = serverSocket.accept();
		System.out.println("Connected to port " + socket);
		System.out.println("The connection is from the port " + connection.getPort());
		out = connection.getOutputStream();
		textLineIn1 = connection.getInputStream();
	//	textLineIn1 = new BufferedReader(new InputStreamReader(connection.getInputStream()));
	}
	private void writeMessage(String message2) throws IOException {		
		try {
	//		message2 = message2 +"\n";
			out.write(message2.getBytes());
			out.flush();
			out.close();
			System.out.println( "Writing done "   + message2 );
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Reply given to the mobile");			
	}
	private String readMessage() throws IOException {
		System.out.println("Reading message from client");
	//	BufferedReader textLineIn1 = new BufferedReader(new InputStreamReader(connection.getInputStream()));
		StringBuffer st = new StringBuffer();	
		int c =0;
		while( c != -1 )							//reading the message from client
		{
			c = textLineIn1.read();
			if(c == -1 )
				break;
			st.append((char)c );
		}
		System.out.println("read is complete");
		message = st.toString();
		System.out.println(message);
	//	textLineIn1.close();
		return message;
	}
	private void processRequest(String message2) throws IOException{
		String Request[] = split(message2);
		if( Request[0].equals("fileBrowser")){
			fileBrowser(Request);
		}
		else if(Request[0].equals("services"))
			sendServices(Request);
		else if(Request[0].equals("authentication")){
			String username = Request[1];
			String password = Request[2];
			System.out.println( "username: " + username + " ::password : " + password );
			//do the authentication
			int status = auth.authenticate(username, password);
			if(status == 1) writeMessage( "authentication\ntrue\n");
			else writeMessage( "authentication\nfalse\n");
			OWNER=username;
		}
		else if( Request[0].equals("VM")){
			VMServices( Request );
			System.out.println( " the check VM satisfied");
			
		}
		else{
			System.out.println( "did not satisfy any ... please check again ");
		}
		
	}
	
	private void VMServices(String request[]) throws IOException {
		String action = request[1];
		System.out.println( action + "*********" );
		
		if( action.equals( "Start") || action.equals("Edit") || action.equals("Remove")|| action.equals("Stop")){
			//send the vm list in the format  VM\n<action>+VM\n ... list....
			//String vmlist = "VM\n"+ action + "VM\nblah1\nblah2\nblah3\nblah4";
			//String user;
			String vmlist = "VM\n"+getVMList();
			vmlist = "VM\n"+ action + vmlist;
			writeMessage( vmlist );
		}
		else if( action.equals("CreateVM")){
			String name = request[2];
			int ram = Integer.parseInt(request[3]);
			int cores = Integer.parseInt(request[4]);
			int hdd = Integer.parseInt(request[5]);
			String os = request[6];
			OS VMOS;
			if(os.equals("1")) VMOS = new OS("WindowsXP");
			else if(os.equals("2")) VMOS = new OS("Ubuntu");
			else VMOS = new OS("Other");
		
			VM newVM = new VM(settings.VMSettings);
			newVM.owner = OWNER;
			newVM.setConfig(name, VMOS, ram, cores, hdd);
			vmm.createVM(newVM);
			writeMessage( "VM\nCreate VM Task has been submitted" );
			
		}
		else if( action.equals("EditVM")){
			String name = request[2];
			int ram = Integer.parseInt(request[3]);
			int cores = Integer.parseInt(request[4]);
			int hdd = Integer.parseInt(request[5]);
			
			VM newVM = new VM(settings.VMSettings);
			newVM.owner = OWNER;
			newVM.setConfig(name, null, ram, cores, hdd);
			vmm.modifyVM(newVM);
			writeMessage( "VM\nEdit VM Task Submitted" );
		}
		else if( action.equals("RemoveVM")){
			String name = request[2];
			VM newVM = new VM(settings.VMSettings);
			newVM.owner = OWNER;
			newVM.setConfig(name);
			vmm.deleteVM(newVM);
			writeMessage( "VM\nRemove VM Task submitted" );
		}
		else if( action.equals("StopVM")){
			String name = request[2];
			VM newVM = new VM(settings.VMSettings);
			newVM.owner = OWNER;
			newVM.setConfig(name);
			vmm.stopVM(newVM);
			writeMessage( "VM\nStopVM Task submitted");
		}
		else if( action.equals("StartVM")){
			String name = request[2];
			VM newVM = new VM(settings.VMSettings);
			newVM.owner = OWNER;
			newVM.setConfig(name);
			vmm.startVM(newVM);
			writeMessage( "VM\nStartVM Task submitted");
		}
		else
			writeMessage( "VM\nsuccess" );
		
	}
	private String getVMList() {
		String list = "";
		
		String query = "SELECT vmname from vms where owner='"+OWNER+"' and status='active'";
		String name="";
		try {
		Statement st;
		st = db.getCon().createStatement();
		
		//log.info("Executing : "+query);
		ResultSet res = st.executeQuery(query);
        
	       while (res.next()) {
	          name = res.getString("vmname");
	          list=list+name+"\n";
	          
		}
	       
	       System.out.println("list : "+list);
		}
	    catch (SQLException e) {
			
			e.printStackTrace();
		}
	    
		return list;
	}
	private void sendServices(String[] request) throws IOException {
		String[] services =  new String[2];
		services[0] = "services";
		services[1] = "fileBrowser";
		
		writeMessage( joinStrings(services) );
		
	}
	private void fileBrowser(String[] request) throws IOException {		
		
		StringBuffer response = new StringBuffer();
		response.append("fileBrowser\n");
		//TODO split the request part and get the directory that has to be made pwd
		String cmd = request[1];
		String cmdResult = null;
		pwd = request[2];
		if( cmd.equals("ls")){
			String fileName = nameFromPwd( request[2]);
			StringBuffer fileContents = new StringBuffer();
			File f = new File( pwd );
			if( f.isFile()){
				FileInputStream finp = new FileInputStream(f);
				int ch;
				do{
					ch = finp.read();
					fileContents.append( (char)ch );
					
				}while( ch !=-1 );
				finp.close();
				response.append("file\n");
				response.append(fileName);
				response.append("\n");
				cmdResult = fileContents.toString();
			}
			else
			{
				response.append("folder\n");
				cmdResult = listFiles( pwd );
			}

		}
		else if( cmd.equals("del")){
			delFile(pwd, request[3]);
			cmdResult = listFiles( pwd );
		}
		else if( cmd.equals("paste")){
			pasteFile(pwd,request[3]);
			cmdResult = listFiles( pwd );
		}
		else if( cmd.equals("save")){
			saveFile( pwd, request[3] );
			cmdResult = "";
			
		}
		
		
		response.append(pwd);
		response.append("\n");
		

		response.append(cmdResult);	
		//delFile(request);
		writeMessage(response.toString());		
	}
	
	private void saveFile(String fName,  String newContents) throws IOException {
		File f = new File( fName );
		FileOutputStream fOut = new FileOutputStream(f);
		fOut.write( newContents.getBytes());
		System.out.println( newContents);
		fOut.close();		
	}
	private void delFile(String pwd, String file) throws IOException{
//		String cmd = "cmd /c del " + pwd + "\\" +file;
		String cmd = "rm -r " + pwd ;
		
		System.out.println(cmd);
		executeCMD( cmd );		

		
	}
	
	private void pasteFile(String pwd2, String file ) throws IOException{
		String cmd = "cp -r " + file + " " + pwd2;
		try {
			executeCMD( cmd );
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	private void cutFile(String pwd2, String file ) throws IOException{
		String cmd = "mv " + file + " " + pwd;
		executeCMD( cmd);
		
	}
	
	
	private String listFiles(String pwd2) throws IOException {
		//String cmd = "cmd /c dir" + " "+ pwd2;
		String cmd = "ls " + pwd2;		
		return readCMDOutput( executeCMD(cmd) );
		
	}
	
	private Process executeCMD(String cmd) throws IOException{
		Runtime run = Runtime.getRuntime();
		Process pr = run.exec(cmd);
		try {
			pr.waitFor();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return pr;
		
	}
	
	private String readCMDOutput( Process pr) throws IOException{
		BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
		String line = "";

		StringBuffer buff = new StringBuffer();
		
		while ((line=buf.readLine())!=null) {
			buff.append(line);
			buff.append("\n");
		}
			
		return buff.toString();
		
	}
	
	private String nameFromPwd( String p ){
		int indexBeg = p.lastIndexOf('/');
		return p.substring(indexBeg + 1);
	}
	
	
	private String[] split(String original) {
	        Vector<String> nodes = new Vector<String>();
	        String separator = "\n";
	//        System.out.println("split start...................");
	        // Parse nodes into vector
	        int index = original.indexOf(separator);
	        while(index>=0) {
	            nodes.addElement( original.substring(0, index) );
	            original = original.substring(index+separator.length());
	            index = original.indexOf(separator);
	        }
	        // Get the last node
	        nodes.addElement( original );
	        // Create splitted string array
	        String[] result = new String[ nodes.size() ];
	        if( nodes.size()>0 ) {
	            for(int loop=0; loop<nodes.size(); loop++)
	            {
	                result[loop] = (String)nodes.elementAt(loop);
	                System.out.println(result[loop]);
	            }
	        }
	        return result;
	    }
	private String joinStrings( String[] strings){
		StringBuffer temp = new StringBuffer();
		for( int i = 0; i<strings.length ; i++){
			temp.append(strings[i]);
			temp.append("\n");
		}
		
		return temp.toString();		
	}
	   public static void main(String args[])
		{
			Server server=new Server();
		    try {
				server.run();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    
		}
}


